#include <3DSReader.h>
#include <vector>
using std::vector;
dsloader::dsloader(const char*filename)
{
	this->level=0;
	this->current_chunk=0;
#ifdef OPEN_FILE_BUFFER
	filebuffer=(char*)malloc(sizeof(char)*OPEN_FILE_BUFFER);
#endif
	this->load(filename);
}
dsloader::dsloader()
{
#ifdef OPEN_FILE_BUFFER
	filebuffer=(char*)malloc(sizeof(char)*OPEN_FILE_BUFFER);
#endif
	this->level=0;
	this->current_chunk=0;
}
dsloader::~dsloader()
{
	list<chunkData*>::iterator i;
	for(i=list_chunk.begin();i!=list_chunk.end();i++)
		delete (chunk*)(*i);
#ifdef OPEN_FILE_BUFFER
	if(filebuffer)
		free(filebuffer);
#endif
}
int dsloader::load(const char* filename) //if load success then return 1 else 0
{
	this->global_fileid=fopen(filename,"r");
	if(global_fileid==0)
		return 0;
#ifdef OPEN_FILE_BUFFER
	if(this->filebuffer)
		setvbuf(this->global_fileid,this->filebuffer,_IOFBF,OPEN_FILE_BUFFER);
#endif
	fread_fd_chunk();
	fclose(this->global_fileid);
	return 1;
}

int dsloader::fread_fd_chunk(uint16_t pre_id)
{
	int size=0;
	common_chunk this_chunk;
	this_chunk.par_id=pre_id;
	fread(&this_chunk.id,1,2,global_fileid);
	fread(&this_chunk.length,4,1,global_fileid);
	size+=6;
	for(int i=0;i<level;++i)
		printf("-");
	printf("%04x,length=%d\n",this_chunk.id,this_chunk.length);
	switch(this_chunk.id)
	{
		case 0x4d4d:
		break;
		case 0x3D3D:case 0xafff:case 0x4100:
		break;
		case 0x4000:
			//数据块的开始
			this->current_chunk=new chunk();
			size+=fread_moduleinfo();
			while(size<this_chunk.length)
			{
				level++;
				size+=fread_fd_chunk(this_chunk.id);	
				level--;
			}
			this->list_chunk.push_back((chunkData*)this->current_chunk);
			//数据块的结束
			break;
		case 0x4110: //顶点列表
			size+=fread_vertex();
			break;
		case 0x4120:
			size+=fread_face();
			//fseek(global_fileid,this_chunk.length-size,SEEK_CUR);
			//size=this_chunk.length;
			break;
		case 0x4140:
			size+=fread_texture();
			break;
		default:
			fseek(global_fileid,this_chunk.length-6,SEEK_CUR);
			return this_chunk.length;
	}
	while(size<this_chunk.length)
	{
		level++;
		size+=fread_fd_chunk(this_chunk.id);	
		level--;
	}
	return size;
}
int dsloader::fread_texture()
{
	uint16_t count;
	fread(&count,1,2,this->global_fileid);
	this->current_chunk->initTexture(count);
	texture_chunk temp;
	for(int i=0;i<count;++i)
	{
		fread(&temp.s,4,1,this->global_fileid);
		fread(&temp.t,4,1,this->global_fileid);
//		printf("(%.2lf,%.2lf)\n",temp.s,temp.t);
		this->current_chunk->append_texture(temp);
	}
	return count*8+2;
}
int dsloader::fread_vertex()
{
	uint16_t count;
	fread(&count,1,2,global_fileid);
	this->current_chunk->initVertex(count);
	for(int i=0;i<count;i++)
	{
		vertex_chunk vertex;
		fread(&vertex.x,4,1,global_fileid);
		fread(&vertex.y,4,1,global_fileid);
		fread(&vertex.z,4,1,global_fileid);
		printf("%.2lf %.2lf %.2lf\n",vertex.x,vertex.y,vertex.z);
		this->current_chunk->append_vertex(vertex);
	}
	return count*12+2;
}
const list<chunkData*>& dsloader::getListChunk()
{
	return this->list_chunk;
}
int dsloader::fread_face()
{
	struct face_chunk face;
	uint16_t count;
	fread(&count,1,2,global_fileid);
	this->current_chunk->initFace(count);
	for(int i=0;i<count;++i)
	{
		fread(&face.one,1,2,global_fileid);
		fread(&face.two,1,2,global_fileid);
		fread(&face.three,1,2,global_fileid);
		fseek(global_fileid,2,SEEK_CUR);
		printf("%d %d %d\n",face.one,face.two,face.three);
		this->current_chunk->append_face(face);
	}
	return count*8+2;
}
int dsloader::fread_moduleinfo()
{
	char name[255];
	int i=0;
	for(;i<255;++i)
	{
		fread(&name[i],1,1,global_fileid);
		if(!name[i])
		{
//			puts(name);
//			putchar('\n');
			break;
		}
	}
	this->current_chunk->setName(name);
	return i+1;
}


chunk::chunk()
{
	vertex=0;
	face=0;
	texture=0;
	_texture_index=0;
	_max_texture_num=0;
	_vertex_index=0;
	_face_index=0;
	_max_face_num=0;
	_max_vertex_num=0;
}
chunk::~chunk()
{
	if(vertex)
		delete[] vertex;
	if(face)
		delete[] face;
	if(texture)
		delete[] texture;
}
int chunk::get_face_length() const
{
	return this->_max_face_num;
}
int chunk::get_vertex_length() const
{
	return this->_max_vertex_num;
}
int chunk::get_texture_length() const
{
	return this->_max_texture_num;
}
void chunk::initVertex(int n)
{
	if(this->vertex)
		delete[] this->vertex;
	this->vertex=0;
	this->_max_vertex_num=0;
	this->_vertex_index=0;
	if(n>0){
		this->vertex=new vertex_chunk[n]{};
		this->_max_vertex_num=n;
	}
}
void chunk::initFace(int n)
{
	if(this->face)
		delete[] this->face;
	this->face=0;
	this->_max_face_num=0;
	this->_face_index=0;
	if(n>0){
		this->face=new face_chunk[n]{};
		this->_max_face_num=n;
	}
}
void chunk::initTexture(int n)
{
	if(this->texture)
		delete[] this->texture;
	this->texture=0;
	this->_texture_index=0;
	this->_max_texture_num=0;
	if(n>0){
		this->texture=new texture_chunk[n]{};
		this->_max_texture_num=n;
	}
}
void chunk::setName(const char* name)
{
	this->name=name;
}
void chunk::append_face(face_chunk& face)
{
	if(_face_index<_max_face_num){
		memcpy(&this->face[_face_index],&face,sizeof(face_chunk));
		_face_index++;
	}
}
void chunk::append_vertex(vertex_chunk& vertex)
{
	if(_vertex_index<_max_vertex_num){
		memcpy(&this->vertex[_vertex_index],&vertex,sizeof(vertex_chunk));
		_vertex_index++;
	}
}
void chunk::append_texture(texture_chunk& texture)
{
	if(_texture_index<_max_texture_num){
		memcpy(&this->texture[_texture_index],&texture,sizeof(texture_chunk));
		_texture_index++;
	}
}
const vertex_chunk* chunk::get_vertex()
{
	return this->vertex;
}
const face_chunk* chunk::get_face()
{
	return this->face;
}
const texture_chunk* chunk::get_texture()
{
	return this->texture;
}
const char* chunk::get_name()
{
	return this->name.c_str();
}
